package com.thread.thread.同步容器;


import java.util.concurrent.ConcurrentLinkedQueue;
//基于链表的非阻塞式队列，因为内部采用cas机制，没有使用锁
//卖票
public class ConcurrentLinkedQueueTest {
	static ConcurrentLinkedQueue list=new ConcurrentLinkedQueue();

	static{
		for (int i=0;i<10000;i++){
			list.offer("票编号"+i);
		}
	}
	public static void main(String[] args) {
		for(int i=0;i<10;i++){
			new Thread(()->{

				while (true){
					String s=(String)list.poll();
					if(s!=null){
						System.out.println("线程号"+Thread.currentThread().getName()+"--销售了"+s);

					}else{
						System.out.println("打印一下"+list.size());
					}
				}


			}).start();
		}



	}
}
/*
	//对于为什么要建立tail节点：个人理解为减少下一次添加元素时递归的次数，不然每次都要从头开始算，因为既然可以认为casTail节点失败，那么此时可能已经中间有很多节点已经存在了，但这个并不影响
	Node数据结构：item   与  next
	new ConcurrentLinkedQueue时候初始化了一个Node head与tail指针指向此Node

	public boolean offer(E e) {
        checkNotNull(e);
        将需要放入队列的数据放进一个新的Node
        final Node<E> newNode = new Node<E>(e);


		将t指针指向tail,p指针指向t
        for (Node<E> t = tail, p = t;;) {
        	//获取p的下一个节点
        	//第一次添加时p的下一个没东西所以是null
        	//第二次添加时第一次进入由于前面已经添加了下一个元素，所以此时的next为上一次添加的元素
			//第二次添加时第二次进入此时p到了新添加节点的位置，下一个节点又将为null
            Node<E> q = p.next;
            if (q == null) {
                //cas操作 p的下一个节点是null则将p指针next指向新节点newNode
                if (p.casNext(null, newNode)) {
                   	//第一次添加很显然p是等于t的两个索引指向同一位置，则直接退出
                   	//第二次时候p的位置已经变化，t还与tail和head在最原始的位置，将tail的指针指到这次新的节点位置
                    if (p != t) // hop two nodes at a time
                        casTail(t, newNode);  // 修改tail节点失败也没关系，因为此时可能已经有其他线程修改了tail节点
                    return true;
                }
                // Lost CAS race to another thread; re-read next
            }
            else if (p == q)
                // We have fallen off list.  If tail is unchanged, it
                // will also be off-list, in which case we need to
                // jump to head, from which all live nodes are always
                // reachable.  Else the new tail is a better bet.
                p = (t != (t = tail)) ? t : head;
            else
                // 第二次添加时进入这，由于此时p，t都还指向刚开始那个节点，所以将tail节点指向第二次即这次加入的节点，继续进入循环
                p = (p != t && t != (t = tail)) ? t : q;
        }
    }

}*/
